package net.bcxuexi.server.stream.inhandle;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import net.bcxuexi.config.Config;
import net.bcxuexi.ports.LoadPorts;
import net.bcxuexi.server.ServerSocketManager;
import net.bcxuexi.server.stream.StreamData;
import net.bcxuexi.server.stream.outwrap.OutputDataWrap;
import net.bcxuexi.tools.MyLog;
import net.bcxuexi.tools.StringUtils;

/**
 * 控制信息输入流数据处理
 */
public class ControlInputStreamHandler extends AbstractInputStreamHandler {

	public ControlInputStreamHandler() {
	}

	@Override
	public void handle() {
		StreamData streamData = null;// 待处理数据

		if (streamData == null) {
			try {
				streamData = take();// 从阻塞队列中取数据，可能会被阻塞
			} catch (InterruptedException e) {
				// 没有取到数据
				return;
			}
		}

		if (streamData == null) {
			MyLog.info("ControlInputStreamHandler队列为空，休息！");
			return;
		}
		// 数据处理
		process(streamData);
		try {
			sleep(80);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 控制信息都是xml的数据，根据根节点进行相应的处理
	 * 
	 * @param streamData
	 */
	private void process(StreamData streamData) {
//		String msg = new String(streamData.data, 1,
//				streamData.total - 1);
		InputStream inputStream = new ByteArrayInputStream(streamData.data, 1,
				streamData.total - 1);// 从第一位开始，第零位为消息类型
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(inputStream);
			String rootName = doc.getDocumentElement().getNodeName();
			
			if ("conn".equals(rootName)) {// 内网客户端请求建立连接
				System.out.println("得到控制消息根节点=" + rootName);
				connProcess(streamData, doc);
			} else if ("connId".equals(rootName)) {// 客户端向服务器发送了connId
				System.out.println("得到控制消息根节点=" + rootName);
				connIdProcess(streamData, doc);
			}else if ("heartbeat".equals(rootName)) {
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 内网客户端请求建立连接，需要向客户端发送connId; 注意：在proxy类型下不用发送
	 * 
	 * @param streamData
	 * @param doc
	 */
	private void connProcess(StreamData streamData, Document doc) {
		NodeList nodeList = doc.getDocumentElement().getChildNodes();
		String socketType = null;
		String clientkey = "";
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			String nodeName = node.getNodeName();
			String nodeValue = node.getTextContent();
			if (StringUtils.isBlack(nodeValue)) {
				nodeValue = "-1";
			}
			if ("type".equals(nodeName)) {
				socketType = nodeValue;
			} else if ("clientKey".equals(nodeName)) {
				clientkey = nodeValue;
				// 验证clientkey是否有效
				boolean has = LoadPorts.getInstance().hasClientKey(clientkey);
				if (!has) {
					streamData.getSocketModel().closeSocket(
							"协议错误，clientkey无效."
									+ streamData.getSocketModel().toString());
					return;
				}
			}
		}
		if (StringUtils.isBlack(socketType)) {// 协议错误，缺少类型
			streamData.getSocketModel().closeSocket(
					"协议错误，缺少类型." + streamData.getSocketModel().toString());
			return;
		}
		streamData.getSocketModel().setClientkey(clientkey);
		streamData.getSocketModel().setType(socketType);
		// 生成connId
		OutputDataWrap outDataWrap = new OutputDataWrap();
		StreamData outputStreamData = outDataWrap.scConnId(streamData
				.getSocketModel());
		if (Config.ServerSocketType.proxy.equals(socketType)) {
			return;
		}
		// 发送connId
		try {
			System.out.println("向客户端发送connId="
					+ outputStreamData.getSocketModel().getConnId());
			streamData.getSocketModel().getWriteStream()
					.addData(outputStreamData);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 服务器端接收到connId之后，需要去验证connId是否正确，不正确则关闭客户端； 同时如果是controlsocket的话需要发送待穿透端口
	 * 
	 * @param streamData
	 * @param doc
	 */
	private void connIdProcess(StreamData streamData, Document doc) {
		NodeList nodeList = doc.getElementsByTagName("connId");
		boolean isSame = false;
		if (nodeList != null) {
			String connId = nodeList.item(0).getTextContent();
			if (!StringUtils.isBlack(connId)
					&& connId.equals(streamData.getSocketModel().getConnId())) {
				isSame = true;
				streamData.getSocketModel().setHasValidConnId(true);
				MyLog.info("connId验证成功，允许建立socket连接");
			} else {
				streamData.getSocketModel().setHasValidConnId(false);
			}
		}
		if (!isSame) {
			// 关闭链接
			streamData.getSocketModel().closeSocket(
					"connId验证错误.关闭连接" + streamData.getSocketModel().toString());
		}
	}

}
